#include"header/abt.h"
#include<stdlib.h>
#include<string.h>
#include<stdio.h>

abt_const abt_num_const(int num){
    abt_const cst = (abt_const)calloc(1,sizeof(abt_const_));
    cst->type = ABT_CONST_NUM;
    cst->cst.num_const = num;
    return cst;
}


abt_var abt_base_var(char *sym){
    abt_var var = (abt_var)calloc(1,sizeof(abt_var_));
    var->sym = sym;
    var->type = ABT_VAR_BASE;
    return var;
}

abt_var abt_field_var(char *sym,char *dsym){
    abt_var var = (abt_var)calloc(1,sizeof(abt_var_));
    var->sym = sym;
    var->type = ABT_VAR_FIELD;
    var->info.field_info.dsym = dsym;
    return var;
}

abt_var abt_array_var(char *sym,abt_exp exp){
    abt_var var = (abt_var)calloc(1,sizeof(abt_var_));
    var->sym = sym;
    var->type = ABT_VAR_ARRAY;
    var->info.array_info.idx_exp = exp;
    return var;
}


abt_exp abt_assgin_exp(abt_var var,abt_exp exp){
    abt_exp aexp = (abt_exp)calloc(1,sizeof(abt_exp_));
    aexp->type = ABT_EXP_ASSGIN;
    aexp->exp.assgin_exp.var = var;
    aexp->exp.assgin_exp.exp = exp;
    return aexp;
}

abt_exp abt_oper_exp(abt_oper op,abt_exp left,abt_exp right){
    abt_exp oexp = (abt_exp)calloc(1,sizeof(abt_exp_));
    oexp->type = ABT_EXP_OPER;
    oexp->exp.oper_exp.op = op;
    oexp->exp.oper_exp.left = left;
    oexp->exp.oper_exp.right = right;
    return oexp;
}

abt_exp abt_var_exp(abt_var var){
    abt_exp exp = (abt_exp)calloc(1,sizeof(abt_exp_));
    exp->type = ABT_EXP_VAR;
    exp->exp.var_exp.var = var;
    return exp;
}

abt_exp abt_const_exp(abt_const cst){
    abt_exp exp = (abt_exp)calloc(1,sizeof(abt_const_));
    exp->type = ABT_EXP_CONST;
    exp->exp.const_exp.cst = cst;
    return exp;
}

abt_exp abt_call_exp(abt_var var,abt_explist explist){
    abt_exp cexp = (abt_exp)calloc(1,sizeof(abt_exp_));
    cexp->type = ABT_EXP_CALL;
    cexp->exp.call_exp.var = var;
    cexp->exp.call_exp.explist = explist;
    return cexp;
}


abt_stmt abt_expression_stmt(abt_exp exp){
    abt_stmt stmt = (abt_stmt)calloc(1,sizeof(abt_stmt_));
    stmt->type = ABT_STMT_EXPRESSION;
    stmt->stmt.expression_stmt.exp = exp;
    return stmt;
}

abt_stmt abt_for_stmt(abt_exp exp1,abt_exp exp2,abt_exp exp3,abt_stmt stmt){
    abt_stmt istmt = (abt_stmt)calloc(1,sizeof(abt_stmt_));
    istmt->type = ABT_STMT_ITERATION;
    istmt->stmt.iteration_stmt.type=ABT_ITER_FOR;
    istmt->stmt.iteration_stmt.exp.for_exp.exp1 = exp1;
    istmt->stmt.iteration_stmt.exp.for_exp.exp2 = exp2;
    istmt->stmt.iteration_stmt.exp.for_exp.exp3 = exp3;
    istmt->stmt.iteration_stmt.stmt = stmt;
    return istmt;
}

abt_stmt abt_while_stmt(abt_exp exp,abt_stmt stmt){
    abt_stmt istmt = (abt_stmt)calloc(1,sizeof(abt_stmt_));
    istmt->type = ABT_STMT_ITERATION;
    istmt->stmt.iteration_stmt.exp.while_exp = exp;
    istmt->stmt.iteration_stmt.stmt = stmt;
    return istmt;
}

abt_stmt abt_selection_stmt(abt_exp exp,abt_stmt tstmt,abt_stmt fstmt){
    abt_stmt stmt = (abt_stmt)calloc(1,sizeof(abt_stmt_));
    stmt->type = ABT_STMT_SELECTION;
    stmt->stmt.selection_stmt.exp = exp;
    stmt->stmt.selection_stmt.tstmt = tstmt;
    stmt->stmt.selection_stmt.fstmt = fstmt;
    return stmt;
}

abt_stmt abt_return_stmt(abt_exp exp){
    abt_stmt stmt = (abt_stmt)calloc(1,sizeof(abt_stmt_));
    stmt->type = ABT_STMT_JUMP;
    stmt->stmt.jump_stmt.type = ABT_JUMP_RETURN;
    stmt->stmt.jump_stmt.args.exp = exp;
    return stmt;
}

abt_stmt abt_break_stmt(){
    abt_stmt stmt = (abt_stmt)calloc(1,sizeof(abt_stmt_));
    stmt->type = ABT_STMT_JUMP;
    stmt->stmt.jump_stmt.type = ABT_JUMP_BREAK;
    return stmt;
}

abt_stmt abt_goto_stmt(){
    abt_stmt stmt = (abt_stmt)calloc(1,sizeof(abt_stmt_));
    stmt->type = ABT_STMT_JUMP;
    stmt->stmt.jump_stmt.type = ABT_JUMP_GOTO;
    return stmt;
}


abt_dec abt_int_dec(char *sym){
    abt_dec dec = (abt_dec)calloc(1,sizeof(abt_dec_));
    dec->type = ABT_DEC_INT;
    dec->sym = sym;
    return dec;
}

abt_dec abt_void_dec(char *sym){
    abt_dec dec = (abt_dec)calloc(1,sizeof(abt_dec_));
    dec->type = ABT_DEC_INT;
    dec->sym = sym;
    return dec;
}

abt_dec abt_array_dec(char *sym,int size,int etype,
                        char *ssym,abt_declist declist){
    abt_dec dec = (abt_dec)calloc(1,sizeof(abt_dec_));
    dec->type = ABT_DEC_ARRAY;
    dec->sym = sym;
    dec->info.array_info.etype = etype;
    dec->info.array_info.ssym = ssym;
    dec->info.array_info.size = size;
    dec->info.array_info.sdeclist = declist;
    return dec;
}

abt_dec abt_function_dec(char *sym,int rtype,abt_declist arglist,
                            abt_stmt cstmt,char *ssym,abt_declist declist){
    abt_dec dec = (abt_dec)calloc(1,sizeof(abt_dec_));
    dec->type = ABT_DEC_FUNCTION;
    dec->sym = sym;
    dec->info.function_info.rtype = rtype;
    dec->info.function_info.arglist = arglist;
    dec->info.function_info.cstmt = cstmt;
    dec->info.function_info.ssym = ssym;
    dec->info.function_info.sdeclist = declist;
    return dec;
}

abt_dec abt_struct_dec(char *sym,char *ssym,abt_declist declist){
    abt_dec dec = (abt_dec)calloc(1,sizeof(abt_dec_));
    dec->type = ABT_DEC_STRUCT;
    dec->sym = sym;
    dec->info.struct_info.ssym = ssym;
    dec->info.struct_info.sdeclist = declist;
    return dec;
}

abt_declist abt_dec_list(abt_dec dec,abt_declist declist){
    abt_declist ndeclist = (abt_declist)calloc(1,sizeof(abt_declist_));
    ndeclist->dec = dec;
    ndeclist->declist = declist;
    return ndeclist;
}

abt_explist abt_exp_list(abt_exp exp,abt_explist explist){
    abt_explist nexplist = (abt_explist)calloc(1,sizeof(abt_explist_));
    nexplist->exp = exp;
    nexplist->explist = explist;
    return nexplist;
}

abt_stmtlist abt_stmt_list(abt_stmt stmt,abt_stmtlist stmtlist){
    abt_stmtlist nstmtlist = (abt_stmtlist)calloc(1,sizeof(abt_stmtlist_));
    nstmtlist->stmt = stmt;
    nstmtlist->stmtlist = stmtlist;
    return nstmtlist;
}

abt_oper abt_op(int type){
    abt_oper op = (abt_oper)calloc(1,sizeof(abt_oper_));
    op->type = type;
    return op;
}



char * abt_dec_type_msg(int type){
    switch (type)
    {
        case ABT_DEC_ARRAY:
            return "Array";
        case ABT_DEC_FUNCTION:
            return "Function";
        case ABT_DEC_INT:
            return "Int";
        case ABT_DEC_STRUCT:
            return "Struct";
        case ABT_DEC_VOID:
            return "Void";
        default:
            return NULL;
    }
}

void log_dec(abt_dec dec){
    puts("Declaration {");
    switch(dec->type){
        case ABT_DEC_VOID:
            puts("\ttype: Void");
            printf("\tidentifier: %s\n",dec->sym);
            puts("}");
            break;
        case ABT_DEC_INT:
            puts("\ttype: Int");
            printf("\tidentifier: %s\n",dec->sym);
            puts("}");
            break;
        case ABT_DEC_STRUCT:
            puts("\ttype: Struct");
            printf("\tidentifier: %s\n",dec->sym);
            printf("\tstruct identifier: %s\n",dec->info.struct_info.ssym);
            puts("}");
            break;
        case ABT_DEC_FUNCTION:
            puts("\ttype: Function");
            printf("\tidentifier: %s\n",dec->sym);
            printf("\treturn type: %s\n",abt_dec_type_msg(dec->info.function_info.rtype));
            puts("}");
            break;
        case ABT_DEC_ARRAY:
            puts("\ttype: Array");
            printf("\tidentifier: %s\n",dec->sym);
            printf("\tarray size: %d\n",dec->info.array_info.size);
            printf("\telement type: %s\n",abt_dec_type_msg(dec->info.array_info.etype));
            if(dec->info.array_info.etype==ABT_DEC_STRUCT){
                printf("\tstruct identifier: %s\n",dec->info.array_info.ssym);
            }
            puts("}");
            break;
        default:
            break;
    }
}

void log_abt(abt_declist declist){
    abt_dec dec = NULL;
    abt_declist dlist = declist;
    while(dlist){
        dec = dlist->dec;
        log_dec(dec);
        dlist = dlist->declist;
    }
}


